#pragma once 

#include <thread>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>

#include <boost/filesystem/convenience.hpp>

#include "../../Integrators/IrradianceCache.h"

#define DELTA_TIME 5

using std::thread;
using std::string;
namespace Engine
{
	namespace Logs
	{
		const string BENCH_MARK_DIRECTORY = "./DataOutput/";
		const string LATEST_UPDATE_DIRECTORY = "./LatestUpdate/"; 
		const string LATEST_UPDATE_File_NAME = "LatestUpdate.txt";


		class SnapShotExtracter
		{
		public:

			SnapShotExtracter(IrradianceCache* p_IC, Camera* p_camera)
			{
				m_startingTime = clock();
				m_Ic = p_IC;
				m_camera = p_camera;
				InitFstreamCsvFormat();
			}

			string GetCurrentDateTime()
			{
				time_t rawtime;
				struct tm timeinfo;
				char buffer[80];

				time(&rawtime);
				localtime_s(&timeinfo, &rawtime);

				strftime(buffer, 80, "%d%m%Y%I%M%S", &timeinfo);
				std::string str(buffer);

				return str;
			}

			void InitFstream()
			{
				time_t _tm = time(NULL);

				struct tm * curtime = localtime(&_tm);

				boost::filesystem::path dir(BENCH_MARK_DIRECTORY);

				if (!(boost::filesystem::exists(BENCH_MARK_DIRECTORY)))
				{
					boost::filesystem::create_directory(BENCH_MARK_DIRECTORY);
				}
				
				string path = BENCH_MARK_DIRECTORY + GetCurrentDateTime() + ".txt";


				m_fileStream.open(path);

				m_snapshotThread = thread(&SnapShotExtracter::CodeSnapshotThreadCsvFormat, this);
			}

			void InitFstreamCsvFormat()
			{
				time_t _tm = time(NULL);

				struct tm * curtime = localtime(&_tm);

				boost::filesystem::path dir(BENCH_MARK_DIRECTORY);

				if (!(boost::filesystem::exists(BENCH_MARK_DIRECTORY)))
				{
					boost::filesystem::create_directory(BENCH_MARK_DIRECTORY);
				}

				boost::filesystem::path updateLatest(LATEST_UPDATE_DIRECTORY);

				if (!(boost::filesystem::exists(LATEST_UPDATE_DIRECTORY)))
				{
					boost::filesystem::create_directory(LATEST_UPDATE_DIRECTORY);
				}

				string latestUpdateFullPath = LATEST_UPDATE_DIRECTORY + LATEST_UPDATE_File_NAME;
				string path = BENCH_MARK_DIRECTORY + GetCurrentDateTime() + ".txt";

				m_fileStream.open(path);
				m_latestUpdate.open(latestUpdateFullPath, ios::out);

				m_snapshotThread = thread(&SnapShotExtracter::CodeSnapshotThreadCsvFormat, this);
			}

			void GetCurrentSnapshot()
			{
				m_fileStream << "---------- \n";
				m_fileStream << GetLocalNetworkRadianceCount() << "\n";
				m_fileStream << "Frame Rate " << GetFrameRate() << "\n";
				m_fileStream << m_camera->eye.toString() << " \n";
			}

			void GetCurrentSnapshotCsvFormat()
			{
				m_fileStream << GetLocalNetworkRadianceCountToCsv() << "," << GetFrameRate() << "," << m_camera->eye.toString() << " \n";
				//m_latestUpdate << GetLocalNetworkRadianceCountToCsv() << "," << GetFrameRate() << "," << m_camera->eye.toString();
				//m_latestUpdate.flush();
			}

			void ProduceHeader()
			{
				m_fileStream << "LocalRadianceCount,GlobalRadianceCount,FrameRate,Position \n";
			}

			void CodeSnapshotThread()
			{
				int index = 0;
				while (!m_sessionEnded)
				{
					GetCurrentSnapshot();

					if (index == 100)
					{
						m_fileStream.flush();
						index = 0;
					}
					else
						index++;
					

					this_thread::sleep_for(std::chrono::seconds(DELTA_TIME));
				}
			}

			void CodeSnapshotThreadCsvFormat()
			{
				ProduceHeader();
				int index = 0;
				while (!m_sessionEnded)
				{
					
					GetCurrentSnapshotCsvFormat();

					if (index == 100)
					{
						m_fileStream.flush();
						index = 0;
					}
					else
						index++;
					this_thread::sleep_for(std::chrono::seconds(DELTA_TIME));
				}
			}

			string GetLocalNetworkRadianceCount()
			{
				return "Local Radiance Points count " + to_string(m_Ic->GetLocalRadianceCount()) + "\n Network Radi	ance Points count " + to_string(m_Ic->GetNetworkRadianceCount()) + "\n";
			}

			string GetLocalNetworkRadianceCountToCsv()
			{
				return to_string(m_Ic->GetLocalRadianceCount()) + "," + to_string(m_Ic->GetNetworkRadianceCount());
			}


			float CalculateFrameRate()
			{
				clock_t currentTime = clock();
				double timeInSeconds = ((double)currentTime - m_startingTime) / (double)CLOCKS_PER_SEC;

				if (m_camera->m_totalCreatedFrames == 0)
					return 0;
				else
					return m_camera->m_totalCreatedFrames / timeInSeconds;
			}

			string GetFrameRate()
			{
				return to_string(CalculateFrameRate());
			}

			void StopBenchMarks()
			{
				m_sessionEnded = true;
			}

			~SnapShotExtracter()
			{}
		private:
			Engine::IrradianceCache* m_Ic;
			Engine::Camera* m_camera;
			std::ofstream  m_fileStream;
			std::ofstream m_latestUpdate;
			clock_t m_startingTime;
			thread m_snapshotThread;
			bool m_sessionEnded = false;
		};
	}
}//Engine

